package com.aizuda.boot.modules.file.service.impl;

import com.aizuda.boot.modules.file.domain.entity.FileConversionCache;
import com.aizuda.boot.modules.file.mapper.FileConversionCacheMapper;
import com.aizuda.boot.modules.file.service.IFileConversionCacheService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.function.Function;

/**
 * 文件转换缓存服务实现类
 * 
 * @author yangshen
 * @date 2025-08-04
 */
@Slf4j
@Service
public class FileConversionCacheServiceImpl extends ServiceImpl<FileConversionCacheMapper, FileConversionCache> 
        implements IFileConversionCacheService {

    @Resource
    private FileConversionCacheMapper conversionCacheMapper;

    @Override
    public FileConversionCache findBySourceFileIdAndType(String sourceFileId, String conversionType) {
        if (!StringUtils.hasText(sourceFileId) || !StringUtils.hasText(conversionType)) {
            return null;
        }
        return conversionCacheMapper.findBySourceFileIdAndType(sourceFileId, conversionType);
    }

    @Override
    public FileConversionCache findBySourceFileKeyAndType(String sourceFileKey, String conversionType) {
        if (!StringUtils.hasText(sourceFileKey) || !StringUtils.hasText(conversionType)) {
            return null;
        }
        return conversionCacheMapper.findBySourceFileKeyAndType(sourceFileKey, conversionType);
    }

    @Override
    public FileConversionCache saveConversionCache(String sourceFileId, String sourceFileKey, String sourceFileMd5,
                                                  String targetFileId, String targetFileKey, String conversionType, Long fileSize) {
        FileConversionCache cache = new FileConversionCache();
        cache.setSourceFileId(sourceFileId);
        cache.setSourceFileKey(sourceFileKey);
        cache.setSourceFileMd5(sourceFileMd5);
        cache.setTargetFileId(targetFileId);
        cache.setTargetFileKey(targetFileKey);
        cache.setConversionType(conversionType);
        cache.setFileSize(fileSize);
        cache.setCreatedTime(LocalDateTime.now());
        cache.setUpdatedTime(LocalDateTime.now());

        // 如果已存在相同的源文件和转换类型，则更新记录
        FileConversionCache existing = null;
        
        // 先按ID查找，如果没有再按Key查找
        if (StringUtils.hasText(sourceFileId)) {
            existing = findBySourceFileIdAndType(sourceFileId, conversionType);
        }
        if (existing == null && StringUtils.hasText(sourceFileKey)) {
            existing = findBySourceFileKeyAndType(sourceFileKey, conversionType);
        }
        
        if (existing != null) {
            cache.setId(existing.getId());
            cache.setCreatedTime(existing.getCreatedTime());
            updateById(cache);
        } else {
            save(cache);
        }

        log.info("保存文件转换缓存成功，源文件ID: {}, 源文件Key: {}, 转换类型: {}, 目标文件Key: {}", 
                sourceFileId, sourceFileKey, conversionType, targetFileKey);
        return cache;
    }

    @Override
    public boolean isCacheValid(FileConversionCache cacheRecord, String currentFileMd5) {
        if (cacheRecord == null) {
            return false;
        }

        // 如果没有MD5信息，暂时认为缓存有效（可以根据实际情况调整策略）
        if (!StringUtils.hasText(cacheRecord.getSourceFileMd5()) || !StringUtils.hasText(currentFileMd5)) {
            log.warn("文件MD5信息缺失，无法验证缓存有效性，源文件ID: {}", cacheRecord.getSourceFileId());
            return true;
        }

        boolean isValid = cacheRecord.getSourceFileMd5().equals(currentFileMd5);
        if (!isValid) {
            log.info("文件转换缓存已失效，源文件已被修改，源文件ID: {}, 缓存MD5: {}, 当前MD5: {}", 
                    cacheRecord.getSourceFileId(), cacheRecord.getSourceFileMd5(), currentFileMd5);
        }

        return isValid;
    }

    @Override
    public int deleteBySourceFileId(String sourceFileId) {
        if (!StringUtils.hasText(sourceFileId)) {
            return 0;
        }
        
        int deleteCount = conversionCacheMapper.deleteBySourceFileId(sourceFileId);
        log.info("删除文件转换缓存，源文件ID: {}, 删除数量: {}", sourceFileId, deleteCount);
        return deleteCount;
    }

    @Override
    public String getOrCreateWordToPdfCache(String sourceFileId, String sourceFileKey, String sourceFileMd5,
                                           Function<String, ConversionResult> converterFunction) {
        
        String conversionType = FileConversionCache.ConversionType.WORD_TO_PDF.getCode();
        
        // 1. 先查找缓存（优先用fileId，如果没有则用fileKey）
        FileConversionCache existingCache = null;
        if (StringUtils.hasText(sourceFileId)) {
            existingCache = findBySourceFileIdAndType(sourceFileId, conversionType);
        } else if (StringUtils.hasText(sourceFileKey)) {
            existingCache = findBySourceFileKeyAndType(sourceFileKey, conversionType);
        }
        
        // 2. 检查缓存是否有效
        if (existingCache != null && isCacheValid(existingCache, sourceFileMd5)) {
            String cacheKey = StringUtils.hasText(sourceFileId) ? sourceFileId : sourceFileKey;
            log.info("使用文件转换缓存，源文件标识: {}, 目标文件Key: {}", cacheKey, existingCache.getTargetFileKey());
            return existingCache.getTargetFileKey();
        }

        // 3. 缓存不存在或已失效，执行转换
        String sourceIdentifier = StringUtils.hasText(sourceFileId) ? sourceFileId : sourceFileKey;
        log.info("文件转换缓存不存在或已失效，开始执行转换，源文件标识: {}", sourceIdentifier);
        
        try {
            // 执行转换函数，转换函数负责文件保存并返回目标文件Key
            ConversionResult result = converterFunction.apply(sourceFileKey);
            if (result == null || result.getTargetFileKey() == null) {
                throw new RuntimeException("文件转换失败，返回结果为空");
            }

            String targetFileKey = result.getTargetFileKey();
            
            // 4. 保存缓存记录
            saveConversionCache(
                StringUtils.hasText(sourceFileId) ? sourceFileId : sourceFileKey, // 如果没有fileId就用fileKey
                sourceFileKey, 
                sourceFileMd5, 
                result.getTargetFileId(),
                targetFileKey, 
                conversionType, 
                result.getFileSize()
            );

            log.info("文件转换完成并保存缓存，源文件标识: {}, 目标文件Key: {}", sourceIdentifier, targetFileKey);
            return targetFileKey;

        } catch (Exception e) {
            log.error("文件转换失败，源文件标识: {}", sourceIdentifier, e);
            throw new RuntimeException("文件转换失败: " + e.getMessage(), e);
        }
    }
}